//-----------------------------------------------------------------------------
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------

using System;
using System.Windows;
using System.Windows.Input;
using Windows7.Multitouch.Manipulation;
using Windows7.Multitouch.WPF;

namespace Tanagram.Behaviors.Touch
{
    /// <summary>
    /// Managing the manipulation of multiple pictures in the same time
    /// </summary>
    class ContextualElementTracker
    {
        //Map between touch ids and picture trackers
        TranslateRotateScaleBehavior moveRotateScaleBehavior;
        private readonly InertialManager inertiaParam = new InertialManager();
        private readonly ManipulationInertiaProcessor manipulationInertiaProcessor = new ManipulationInertiaProcessor(ProcessorManipulations.ALL, Factory.CreateTimer());

        bool FingerFlag;
        bool MouseFlag;

        public ContextualElementTracker(TranslateRotateScaleBehavior moveRotateScaleBehavior, FrameworkElement element)
        {
            this.moveRotateScaleBehavior = moveRotateScaleBehavior;

            element.Loaded += (s, e) =>
            { 
                Factory.EnableStylusEvents(Application.Current.MainWindow);
                element.StylusDown += ProcessDown;
                element.StylusUp += ProcessUp;
                element.StylusMove += ProcessMove;
                element.StylusLeave += ProcessLeave;
                element.MouseDown += ProcessDown;
                element.MouseUp += ProcessUp;
                element.MouseLeave += ProcessLeave;
                element.MouseMove += ProcessMove;

            };
            manipulationInertiaProcessor.ManipulationStarted += ProcessManipulationStarted;
            manipulationInertiaProcessor.ManipulationCompleted += ProcessManipulationCompleted;
            manipulationInertiaProcessor.ManipulationDelta += ProcessManipulationDelta;
            manipulationInertiaProcessor.BeforeInertia += OnBeforeInertia;
        }

        public event EventHandler<ManipulationDeltaEventArgs> ManipulationCompleted = (s, e) => { };

        public void ProcessDown(object sender, StylusEventArgs args)
        {
            FingerFlag = true;
            moveRotateScaleBehavior.BringToFront();
            Point touchLocation = moveRotateScaleBehavior.GetPosition(args);
            manipulationInertiaProcessor.ProcessDown((uint)args.StylusDevice.Id, touchLocation.ToDrawingPointF());
        }

        public void ProcessUp(object sender, StylusEventArgs args)
        {
            FingerFlag = false;
            Point touchLocation = moveRotateScaleBehavior.GetPosition(args);
            manipulationInertiaProcessor.ProcessUp((uint)args.StylusDevice.Id, touchLocation.ToDrawingPointF());
        }

        public void ProcessMove(object sender, StylusEventArgs args)
        {
            Point touchLocation = moveRotateScaleBehavior.GetPosition(args);
            manipulationInertiaProcessor.ProcessMove((uint)args.StylusDevice.Id, touchLocation.ToDrawingPointF());
        }
        public void ProcessLeave(object sender, StylusEventArgs args)
        {
            FingerFlag = false;
            Point touchLocation = moveRotateScaleBehavior.GetPosition(args);
            manipulationInertiaProcessor.ProcessUp((uint)args.StylusDevice.Id, touchLocation.ToDrawingPointF());
        }
        public void ProcessDown(object sender, MouseEventArgs args)
        {
            if (!FingerFlag)
            {
                MouseFlag = true;
                moveRotateScaleBehavior.BringToFront();
                Point touchLocation = args.GetPosition(null);
                manipulationInertiaProcessor.ProcessDown(255, touchLocation.ToDrawingPointF());
            }
        }
        public void ProcessUp(object sender, MouseEventArgs args)
        {
            MouseFlag = false;
            if (!FingerFlag)
            {
                Point touchLocation = args.GetPosition(null);
                manipulationInertiaProcessor.ProcessUp(255, touchLocation.ToDrawingPointF());
            }
        }
        public void ProcessMove(object sender, MouseEventArgs args)
        {
            if (MouseFlag)
            {
                Point touchLocation = args.GetPosition(null);
                manipulationInertiaProcessor.ProcessMove(255, touchLocation.ToDrawingPointF());
            }
        }
        public void ProcessLeave(object sender, MouseEventArgs args)
        {
            MouseFlag = false;
            if (!FingerFlag)
            {
                Point touchLocation = args.GetPosition(null);
                manipulationInertiaProcessor.ProcessUp(255, touchLocation.ToDrawingPointF());
            }
        }



        private void ProcessManipulationStarted(object sender, ManipulationStartedEventArgs e)
        {
            inertiaParam.Reset();
        }
        private void ProcessManipulationDelta(object sender, ManipulationDeltaEventArgs e)
        {
            ManipulationCompleted(sender, e);
            inertiaParam.Update(e, 0.4F);
        }
        private void ProcessManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
        {
            inertiaParam.Stop();
        }

        //Fingers removed, start inertia
        void OnBeforeInertia(object sender, BeforeInertiaEventArgs e)
        {
            manipulationInertiaProcessor.InertiaProcessor.InertiaTimerInterval = 15;
            manipulationInertiaProcessor.InertiaProcessor.MaxInertiaSteps = 500;
            manipulationInertiaProcessor.InertiaProcessor.InitialVelocity = inertiaParam.InitialVelocity;
            manipulationInertiaProcessor.InertiaProcessor.DesiredDisplacement = inertiaParam.InitialVelocity.Magnitude * 250;
            manipulationInertiaProcessor.InertiaProcessor.InitialAngularVelocity = inertiaParam.InitialAngularVelocity * 20F / (float)Math.PI;
            manipulationInertiaProcessor.InertiaProcessor.DesiredRotation = Math.Abs(inertiaParam.InitialAngularVelocity * manipulationInertiaProcessor.InertiaProcessor.InertiaTimerInterval * 540F / (float)Math.PI);
            manipulationInertiaProcessor.InertiaProcessor.InitialExpansionVelocity = inertiaParam.InitialExpansionVelocity * 15;
            manipulationInertiaProcessor.InertiaProcessor.DesiredExpansion = Math.Abs(inertiaParam.InitialExpansionVelocity * 4F);
        }
    }
}